package com.wzl.service.impl;

import com.wzl.common.PubException;
import com.wzl.common.errcode.ErrorCodeEnum;
import com.wzl.common.pojo.UserPojo;
import com.wzl.mapper.MbBatchInsertMapper;
import com.wzl.service.MbBatchInsertService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 批量插入数据接口实现
 *
 * @author weizhongli
 * @since 2022-08-29 16:36
 */
@Slf4j
@Service
public class MbBatchInsertServiceImpl implements MbBatchInsertService {

    @Resource
    private MbBatchInsertMapper mbBatchInsertMapper;

    @Resource
    private SqlSessionTemplate sqlSessionTemplate;

    @Autowired
    private ThreadPoolExecutor executor;

    @Override
    @Transactional(rollbackFor = PubException.class)
    public UserPojo selectById(int id) throws PubException {
        try {
           return mbBatchInsertMapper.selectById(id);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("BatchInsertServiceImpl.selectById.error=",e);
            throw new PubException(ErrorCodeEnum.UNKNOWN_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = PubException.class)
    public int batchAdd1() throws PubException {
        try {
            List<UserPojo> list = new ArrayList<>();

            long startTime = System.currentTimeMillis();    //获取开始时间

            for (int i = 0; i < 10000; i++) {
                UserPojo userPojo = new UserPojo();
                userPojo.setId(i);
                userPojo.setName("测试数据"+ i);
                userPojo.setPassword(i);
                list.add(userPojo);
            }

            /**
             * Cause: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (8866773 > 1048576).
             * You can change this value on the server by setting the max_allowed_packet' variable.
             */

            int i = mbBatchInsertMapper.batchAdd1(list);

            long endTime = System.currentTimeMillis();    //获取结束时间

            System.out.println("程序运行时间：" + (endTime - startTime) + "ms");    //输出程序运行时间


            return i;
        } catch (Exception e) {
            e.printStackTrace();
            throw new PubException(ErrorCodeEnum.BATCH_ADD_ERROR);
        }
    }


    @Override
    @Transactional(rollbackFor = PubException.class)
    public int batchAdd2() throws PubException {
        try {
            //ArrayList<UserPojo> list = new ArrayList<>();

            long startTime = System.currentTimeMillis();    //获取开始时间

            int num = 0;
            for (int i = 0; i < 100000; i++) {
                UserPojo userPojo = new UserPojo();
                userPojo.setId(i);
                userPojo.setName("测试数据"+ i);
                userPojo.setPassword(i);
                num += mbBatchInsertMapper.batchAdd2(userPojo);
            }

            long endTime = System.currentTimeMillis();    //获取结束时间
            System.out.println("程序运行时间：" + (endTime - startTime) + "ms");    //输出程序运行时间
            return num;

            /**
             * 程序运行时间：32765ms
             */

        } catch (Exception e) {
            e.printStackTrace();
            throw new PubException(ErrorCodeEnum.BATCH_ADD_ERROR);
        }
    }


    @Override
    @Transactional(rollbackFor = PubException.class)
    public int batchAdd3() throws PubException {
        try {
            long startTime = System.currentTimeMillis();    //获取开始时间

            SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);

            int num = 0;
            try {
                for (int i = 0; i < 100000; i++) {
                    UserPojo userPojo = new UserPojo();
                    userPojo.setId(i);
                    userPojo.setName("测试数据" + i);
                    userPojo.setPassword(i);
                    num += mbBatchInsertMapper.batchAdd3(userPojo);
                    if (i % 1000 == 0 || i == i - 1) {
                        //手动每1000条提交一次，提交后无法回滚
                        session.commit();
                        //清理缓存，防止溢出
                        session.clearCache();
                    }
                }
            } catch (Exception e) {
                //没有提交的数据可以回滚
                session.rollback();
                log.error("AiFileParsingDao.batchInsertFileDetail.error=", e);
//                    throw new AiAcctException(AiStreamErrorCodeEnum.DAO_INSERT_FILE_DETAIL_ERROR);
            } finally {
                session.close();
            }

            long endTime = System.currentTimeMillis();    //获取结束时间
            System.out.println("程序运行时间：" + (endTime - startTime) + "ms");    //输出程序运行时间


            return num;

            /**
             * 程序运行时间：31910ms 34432ms
             */

        } catch (Exception e) {
            e.printStackTrace();
            throw new PubException(ErrorCodeEnum.BATCH_ADD_ERROR);
        }
    }


    @Override
    @Transactional(rollbackFor = PubException.class)
    public int batchAdd4() throws PubException {
        try {

            ArrayList<UserPojo> list = new ArrayList<>();
            for (int i = 0; i < 100000; i++) {
                UserPojo userPojo = new UserPojo();
                userPojo.setId(i);
                userPojo.setName("测试数据" + i);
                userPojo.setPassword(i);
                list.add(userPojo);
            }

            long startTime = System.currentTimeMillis();    //获取开始时间

            SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);

            int num = 0;
            try {
                for (int i = 0; i < list.size(); i++) {
                    num += mbBatchInsertMapper.batchAdd4(list.get(i));
                    if (i % 5000 == 0 || i == i - 1) {
                        //手动每1000条提交一次，提交后无法回滚
                        session.commit();
                        //清理缓存，防止溢出
                        session.clearCache();
                    }
                }
            } catch (Exception e) {
                    //没有提交的数据可以回滚
                    session.rollback();
                    log.error("AiFileParsingDao.batchInsertFileDetail.error=", e);
//                    throw new AiAcctException(AiStreamErrorCodeEnum.DAO_INSERT_FILE_DETAIL_ERROR);
                } finally {
                    session.close();
                }

            long endTime = System.currentTimeMillis();    //获取结束时间
            System.out.println("程序运行时间：" + (endTime - startTime) + "ms");    //输出程序运行时间

            return num;

            /**
             * 程序运行时间：27562ms 35524ms 29080ms 37174ms
             */

        } catch (Exception e) {
            e.printStackTrace();
            throw new PubException(ErrorCodeEnum.BATCH_ADD_ERROR);
        }
    }


    @Override
    @Transactional(rollbackFor = PubException.class)
    public int batchAdd5() throws PubException {
        try {

            List<UserPojo> list = new ArrayList<>();
            for (int i = 0; i < 100000; i++) {
                UserPojo userPojo = new UserPojo();
                userPojo.setId(i);
                userPojo.setName("测试数据" + i);
                userPojo.setPassword(i);
                list.add(userPojo);
            }

            long startTime = System.currentTimeMillis();    //获取开始时间

            int count = list.size()/5000 + (list.size() % 5000 > 0 ? 1 : 0);
            log.info("需要循环次数,{}", count);

            int num = 0;
            for (int i = 0; i < count; i++) {
                num += mbBatchInsertMapper.batchAdd5(list.stream().skip(i*5000).limit(5000).collect(Collectors.toList()));
            }

            long endTime = System.currentTimeMillis();    //获取结束时间
            System.out.println("程序运行时间：" + (endTime - startTime) + "ms");    //输出程序运行时间

            return num;

            /**
             * 程序运行时间：7626ms 8513ms
             */

        } catch (Exception e) {
            e.printStackTrace();
            throw new PubException(ErrorCodeEnum.BATCH_ADD_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = PubException.class)
    public int batchAdd6() throws PubException {
        try {

            List<UserPojo> list = new ArrayList<>();
            for (int i = 0; i < 100000; i++) {
                UserPojo userPojo = new UserPojo();
                userPojo.setId(i);
                userPojo.setName("测试数据" + i);
                userPojo.setPassword(i);
                list.add(userPojo);
            }

            long startTime = System.currentTimeMillis();    //获取开始时间

            int count = list.size()/5000 + (list.size() % 5000 > 0 ? 1 : 0);
            log.info("需要循环次数,{}", count);

            for (int i = 0; i < count; i++) {
                final int finalI = i;
                Thread thread = new Thread(() -> {
                    try {
                        long start1 = System.currentTimeMillis();
                        mbBatchInsertMapper.batchAdd5(list.subList(finalI * 5000, (finalI + 1) * 5000));
                        long end1 = System.currentTimeMillis();
                        //log.info("本次花费时间,{}", end1 - start1);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });


                try {
                    executor.submit(thread);
                } catch (Exception e) {
                    log.info(e.getMessage());
                }
            }

            long endTime = System.currentTimeMillis();    //获取结束时间
            log.info("程序运行时间：" + (endTime - startTime) + "ms");    //输出程序运行时间

            //return Integer.parseInt(((endTime - startTime) + "ms"));
            return (int) (endTime - startTime);

            /**
             * 程序运行时间：7626ms 8513ms
             */

        } catch (Exception e) {
            e.printStackTrace();
            throw new PubException(ErrorCodeEnum.BATCH_ADD_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = PubException.class)
    public int batchAdd7() throws PubException {
        try {
            List<UserPojo> list = new ArrayList<>();
            for (int i = 0; i < 100000; i++) {
                UserPojo userPojo = new UserPojo();
                userPojo.setId(i);
                userPojo.setName("测试数据" + i);
                userPojo.setPassword(i);
                list.add(userPojo);
            }

            long startTime = System.currentTimeMillis();    //获取开始时间

            int count = list.size()/5000 + (list.size() % 5000 > 0 ? 1 : 0);
            log.info("需要循环次数,{}", count);

            int sum = 0;
            for (int i = 0; i < count; i++) {
                final int finalI = i;
                Future<Integer> future = executor.submit(() -> {
                   int s = mbBatchInsertMapper.batchAdd5(list.subList(finalI * 5000, (finalI + 1) * 5000));
                    return s;
                });
                Integer integer = future.get();
                sum += integer;
            }
            log.info("总插入条数----------" + sum);
            long endTime = System.currentTimeMillis();    //获取结束时间
            log.info("程序运行时间：" + (endTime - startTime) + "ms");    //输出程序运行时间
            return sum;
        } catch (Exception e) {
            e.printStackTrace();
            throw new PubException(ErrorCodeEnum.BATCH_ADD_ERROR);
        }
    }

}